package msghandler

import (
	"fmt"
	"reflect"
	"sync"

	"gitee.com/night-tc/gobige/common"
	"gitee.com/night-tc/gobige/logger"
	"gitee.com/night-tc/gobige/msgdef"
	"gitee.com/night-tc/gobige/safecontainer"
)

/*
KeyHandlers 支持按key分组注册和处理消息的消息处理器
*/
type KeyHandlers struct {
	MsgHandler
}

// NewKeyHandler 创建一个KeyHandlers对象
// KeyHandlers 支持按key分组注册和处理消息的消息处理器
func NewKeyHandler() *KeyHandlers {
	return &KeyHandlers{
		MsgHandler: MsgHandler{
			msgFireInfo:  safecontainer.NewSafeListT[*msgFireInfo](),
			rpcFireInfo:  safecontainer.NewSafeListT[*rpcFireInfo](),
			srvFireInfo:  safecontainer.NewSafeListT[*srvFireInfo](),
			defaultFuncs: make([]reflect.Value, 0, 10),
			msgChan:      make(chan bool, 1),
		},
	}
}

// ReKeyMsgProc 清除key对应的处理函数
func (this *KeyHandlers) ReKeyMsgProc(key string) {
	this.msgFuncs.Delete(key)
	this.rpcFuncs.Delete(key)
	this.srvFuncs.Delete(key)
	// 清除key对应的处理函数
}

// RegMsgProc 注册消息处理对象，默认key为空
func (this *KeyHandlers) RegMsgProc(proc interface{}) {
	this.RegMsgProcByKey("", proc)
}

// RegMsgProcByKey 按key注册消息处理对象
func (this *KeyHandlers) RegMsgProcByKey(key string, proc interface{}) {

	v := reflect.ValueOf(proc)
	t := reflect.TypeOf(proc)

	for i := 0; i < t.NumMethod(); i++ {
		methodName := t.Method(i).Name

		//MsgProc前缀的所有方法
		msgName, msgHandler, err := GetPreFunc(MSG_PREFIX, methodName, v.MethodByName(methodName))
		if err == nil {
			li := getHandlerList(&this.msgFuncs, key)
			SetHandlerFunc(li, msgName, msgHandler)
			continue
		}

		// 判断是否是RPC处理函数
		msgName, msgHandler, err = GetPreFunc(RPC_PREFIX, methodName, v.MethodByName(methodName))
		if err == nil {
			li := getHandlerList(&this.rpcFuncs, key)
			SetHandlerFunc(li, msgName, msgHandler)
			continue
		}
		// 判断是否是Srv处理函数
		msgName, msgHandler, err = GetPreFunc(SRV_PREFIX, methodName, v.MethodByName(methodName))
		if err == nil {
			li := getHandlerList(&this.srvFuncs, key)
			SetHandlerFunc(li, msgName, msgHandler)
			continue
		}
	}

	this.addDefaultFunc(proc)
}

// DoMsg 将缓冲的消息一次性处理
func (this *KeyHandlers) DoMsg() {

	var procName string
	var info interface{}
	var err error
	var msgh IMsgHandler
	defer func() {
		if GetRecover() {
			if err := recover(); err != nil {
				logger.Error(err, procName)
				buf := common.StackTrace()
				common.OnRecover(err, buf, info)
				if msgh != nil && msgh.GetMsgOwner() != nil {
					msgh.GetMsgOwner().OnPanic(common.GetError(err))
				}
			}
		}
	}()

	for {
		info, err = this.msgFireInfo.Pop()
		if err != nil {
			break
		}
		msginfo := info.(*msgFireInfo)
		procName = msginfo.name
		msgh = msginfo.GetHandler()
		e := msginfo.handler.DoNormalMsg(msginfo.name, msginfo.content)
		if e != nil {
			logger.Error(e)
		}
	}

	for {
		info, err = this.rpcFireInfo.Pop()
		if err != nil {
			break
		}
		rpcinfo := info.(*rpcFireInfo)
		procName = rpcinfo.methodName
		msgh = rpcinfo.GetHandler()
		e := rpcinfo.handler.DoRPCMsg(rpcinfo.methodName, rpcinfo.content)
		if e != nil {
			logger.Error(e)
		}
	}

	for {
		info, err = this.srvFireInfo.Pop()
		if err != nil {
			break
		}
		msginfo := info.(*srvFireInfo)
		procName = msginfo.methodName
		msgh = msginfo.GetHandler()
		msginfo.handler.DoSrvMsg(msginfo.methodName, msginfo.req, msginfo.msg)

	}
}

// DoNormalMsg 立即触发普通消息，支持多key分发
func (this *KeyHandlers) DoNormalMsg(methodName string, content msgdef.IMsg) error {
	if this.MsgOwner != nil {
		this.MsgOwner.OnMsgBefore(methodName, content)
		defer this.MsgOwner.OnMsged(methodName, content)
	}
	isrun := false
	args := []reflect.Value{reflect.ValueOf(content)}
	this.msgFuncs.Range(func(key, value any) bool {
		li := value.(*sync.Map)
		ifuncs, ok := li.Load(methodName)
		if ok {
			for _, f := range ifuncs.([]reflect.Value) {
				f.Call(args)
				isrun = true
			}
		}
		return true
	})
	if !isrun {
		if len(this.defaultFuncs) == 0 {
			//如果是心跳，没有处理就没有处理，不做error输出
			if methodName == "HeartBeat" {
				return nil
			}
			return fmt.Errorf("Cant find handler %s", methodName)
		}

		for _, f := range this.defaultFuncs {
			if f.IsValid() {
				f.Call([]reflect.Value{reflect.ValueOf(content)})
			}
		}
	}
	return nil
}

// DoRPCMsg 立即触发RPC消息，支持多key分发
func (this *KeyHandlers) DoRPCMsg(methodName string, content msgdef.IMsg) error {
	if this.MsgOwner != nil {
		this.MsgOwner.OnRpcBefore(methodName, content)
		defer this.MsgOwner.OnRpced(methodName, content)
	}

	args := []reflect.Value{reflect.ValueOf(content)}
	this.rpcFuncs.Range(func(key, value any) bool {
		li := value.(*sync.Map)
		ifuncs, ok := li.Load(methodName)
		if ok {
			for _, f := range ifuncs.([]reflect.Value) {
				outVal := f.Call(args)
				if this.MsgOwner != nil &&
					len(outVal) > 0 && outVal[0].CanInterface() {
					if err, ok := outVal[0].Interface().(error); ok && err != nil {
						this.MsgOwner.OnRpcReturn(content, err)
					} else if outVal[0].Interface() == nil {
						this.MsgOwner.OnRpcReturn(content, nil)
					}
				}
			}
		}
		return true
	})
	return nil
}

// DoSrvMsg 调用Srv_前缀的函数，支持多key分发
func (this *KeyHandlers) DoSrvMsg(methodName string, req, msg msgdef.IMsg) {
	args := []reflect.Value{reflect.ValueOf(req), reflect.ValueOf(msg)}
	this.srvFuncs.Range(func(key, value any) bool {
		li := value.(*sync.Map)
		ifuncs, ok := li.Load(methodName)
		if ok {
			for _, f := range ifuncs.([]reflect.Value) {
				outVal := f.Call(args)
				if this.MsgOwner != nil &&
					len(outVal) > 0 && outVal[0].CanInterface() {
					if err, ok := outVal[0].Interface().(error); ok && err != nil {
						this.MsgOwner.OnSrvReturn(req, msg, err)
					} else if outVal[0].Interface() == nil {
						this.MsgOwner.OnSrvReturn(req, msg, nil)
					}
				}
			}
		}
		return true
	})
}

// FireMsg 触发消息, 保证不被挂起
func (this *KeyHandlers) FireMsg(name string, content msgdef.IMsg) {
	if this == nil {
		return
	}
	msg := &msgFireInfo{
		handler: this,
		name:    name,
		content: content,
	}
	this.fireMsg(msg)
	select {
	case this.msgChan <- true:
	default:
	}
}

// FireRPC 触发消息, 保证不被挂起
func (this *KeyHandlers) FireRPC(method string, content msgdef.IMsg) {
	msg := &rpcFireInfo{
		handler:    this,
		methodName: method,
		content:    content,
	}
	this.fireRPC(msg)
	select {
	case this.msgChan <- true:
	default:
	}
}

// FireSrv 触发Srv_前缀的函数,保证不被挂起
func (this *KeyHandlers) FireSrv(name string, req, msg msgdef.IMsg) {
	srvmsg := &srvFireInfo{
		handler:    this,
		methodName: name,
		req:        req,
		msg:        msg,
	}
	this.fireSrv(srvmsg)
	select {
	case this.msgChan <- true:
	default:
	}
}
